using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.AccessControl;
using TripleA.Core.Interfaces.Exceptions;

namespace TripleA.Core.Extensions.FileSystem
{
    public abstract class FileSystemPermissionStepBase<T> : StepBase<T>
    {
        protected bool GetPermissionExceptions(string identity, 
                                               AccessControlType accessType, 
                                               FileSystemRights expected,
                                               IList<FileSystemAccessRule> rules,
                                               out IEnumerable<KeyValuePair<FileSystemRights, bool>> exceptions)
        {
            if (!rules.Any())
                throw new ExpectationException("No rights found for '{0}'", identity);

            var granted = rules.SingleOrDefault(rule => rule.AccessControlType == accessType);

            if (granted == null)
                throw new ExpectationException("No '{0}' rights granted for '{1}'", accessType, identity);

            var grantedRights = GetRights(granted.FileSystemRights);
            var expectedRights = GetRights(expected).Where(entry => entry.Value);
            exceptions = expectedRights.Where(er => grantedRights.ContainsKey(er.Key) && !grantedRights[er.Key]).ToList();

            return exceptions.Any();
        }

        protected string Summarise(IEnumerable<KeyValuePair<FileSystemRights, bool>> rights)
        {
            return string.Join(", ", rights.Select(ex => ex.Key.ToString()).ToArray());
        }

        private static Dictionary<FileSystemRights, bool> GetRights(FileSystemRights rights)
        {
            return Enum.GetValues(typeof(FileSystemRights)).Cast<FileSystemRights>().Distinct().ToDictionary(
                fsr => fsr,
                fsr => (rights & fsr) == fsr
                );
        }
    }
}